package games.checkers;

import games.checkers.chipPath.pathNode;
import games.checkers.gameColors.colorScheme;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.RenderingHints;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.util.ArrayList;

import javax.swing.JPanel;

public class checkersBoard extends JPanel implements MouseListener, MouseMotionListener
{
	private checkers program;
	private chipManager chipMan;
	private Dimension boardDims = new Dimension(512,512);

	private colorScheme colors;
	private ArrayList<boardTile> tileList = new ArrayList<boardTile>(32);
	private Dimension tileDim = new Dimension(64,64);
	private int [][] tileLoc = new int [2][32];;
	private Integer [][] forward = new Integer [2][32]; 
	private Integer [][] backward = new Integer [2][32];
	
	private ArrayList<ArrayList<pathNode>> validMoves = new ArrayList<ArrayList<pathNode>>(0);
	
	private chip selectedChip;
	
	@Override
	public void mouseClicked(MouseEvent arg0) 
	{
	}

	@Override
	public void mouseEntered(MouseEvent arg0) 
	{
		//remove all highlighted tiles
		for (int i=31; i>=0; --i)((boardTile)tileList.get(i)).highlight(false);
	}

	@Override
	public void mouseExited(MouseEvent arg0) 
	{
	}

	@Override
	public void mousePressed(MouseEvent arg0) 
	{
		//is it on a tile?
		int t = whichTile(arg0.getPoint());
		//is there a chip on the tile?
		selectedChip = chipMan.chipOnTile(t);
		if (selectedChip == null) return;
		if (selectedChip.player() != chipMan.currentPlayer()) selectedChip = null;
	}

	@Override
	public void mouseReleased(MouseEvent arg0) 
	{
		// if no chip is selected do nothing
		if (selectedChip == null) return; 
		
		//is it on a tile?
		int t = whichTile(arg0.getPoint());
		
		//which path is the tile in?
		pathNode node;
		ArrayList<pathNode> path;
		boolean foundPath = false;
		for (int i=0;i < validMoves.size(); i++)
		{
			path = (ArrayList<pathNode>) validMoves.get(i);
			for (int j=0; j < path.size(); j++)
			{
				node = (pathNode) path.get(j);
				if ((node.tile == t) && (node.action == chipPath.end))
				{
					foundPath = true;
					break;
				}
			}
			if (foundPath == true) 
			{
				//apply the move
				chipMan.applyPath(path);
				break;
			}
			else
			{
				//move the chip back to it's starting spot
				selectedChip.setTile(selectedChip.getTile());
			}
			
		}
		
		// regenerate moves
		chipMan.generateMoves();
		
		//clear the chip from memory - the move is made
		selectedChip = null;
		repaint();
		program.redBin().repaint();
		program.whiteBin().repaint();
	}
	
	@Override
	public void mouseDragged(MouseEvent arg0) 
	{
		if (selectedChip != null) selectedChip.moveTo(arg0.getPoint());
		repaint();
	}

	@Override
	public void mouseMoved(MouseEvent arg0) 
	{
		//remove all highlighted tiles
		for (int i=31; i>=0; --i)((boardTile)tileList.get(i)).highlight(false);
		
		//highlight the tiles that a player is allowed to move
		int t = whichTile(arg0.getPoint());
		byte currentplayer = chipMan.currentPlayer();
		chip theChip = chipMan.chipOnTile(t);
		if ((theChip != null) && (currentplayer == theChip.player())) 
		{
			validMoves = theChip.validPaths();
			pathNode node;
			ArrayList<pathNode> path;
			for (int p=0;p < validMoves.size();p++)
			{
				path = validMoves.get(p);
				if (path.size() < 3) continue; 
				for (int m=0;m < path.size();m++)
				{
					node = path.get(m);
					(tileList.get(node.tile)).highlight(true);
				}
			}
		} else chipMan.generateMoves();
		repaint();
	}
	
	public checkersBoard(checkers prog)
	{
		//setBackground(new Color(160,82,45));
		program = prog;
		colors = program.colorScheme();
		chipMan = program.chipManager();
		setSize(boardDims);
		setPreferredSize(boardDims);
		initializeTiles();
		addMouseListener(this);
		addMouseMotionListener(this);
	}
	
	 private void initializeTiles() 
	 {
		 tileList.clear();
//		 int [] spacing = new int [] {31,95,159,223,287,351,415,479}; 
//		 tileLoc[0] = new int [] 
//		              {95,223,351,479,
//				       31,159,287,415,
//				       95,223,351,479,
//				       31,159,287,415,
//				       95,223,351,479,
//				       31,159,287,415,
//				       95,223,351,479,
//				       31,159,287,415};
//		 tileLoc[1] = new int []
//		              {31,31,31,31, 
//				       95,95,95,95,
//				       159,159,159,159,
//				       223,223,223,223,
//				       287,287,287,287,
//				       351,351,351,351,
//				       415,415,415,415,
//				       479,479,479,479};
		 int [] tileX = new int []
			              {1,3,5,7,
					       0,2,4,6,
					       1,3,5,7,
					       0,2,4,6,
					       1,3,5,7,
					       0,2,4,6,
					       1,3,5,7,
					       0,2,4,6};
		 int [] tileY = new int []
			              {0,0,0,0, 
					       1,1,1,1,
					       2,2,2,2,
					       3,3,3,3,
					       4,4,4,4,
					       5,5,5,5,
					       6,6,6,6,
					       7,7,7,7};
		 //moving forward/left for player 1 (backward/right for player 2)
		 forward[0] = new Integer [] 
		              {-1,-1,-1,-1,
				       -1,0,1,2,
				       4,5,6,7,
				       -1,8,9,10,
				       12,13,14,15,
				       -1,16,17,18,
				       20,21,22,23,
				       -1,24,25,26};
		//moving forward/right for player 1 (backward/left for player 2)
		 forward[1] = new Integer []
		              {-1,-1,-1,-1,
				       0,1,2,3,
				       5,6,7,-1,
				       8,9,10,11,
				       13,14,15,-1,
				       16,17,18,19,
				       21,22,23,-1,
				       24,25,26,27};
		//moving backward/left for player 1 (forward/right for player 2)
		 backward[0] = new Integer [] 
		               {4,5,6,7,
				        -1,8,9,10,
				        12,13,14,15,
				        -1,16,17,18,
				        20,21,22,23,
				        -1,24,25,26,
				        28,29,30,31,
				        -1,-1,-1,-1};
		//moving backward/right for player 1 (forward/left for player 2)
		 backward[1] = new Integer [] 
		               {5,6,7,-1,
				        8,9,10,11,
				        13,14,15,-1,
				        16,17,18,19,
				        21,22,23,-1,
				        24,25,26,27,
				        29,30,31,-1,
				        -1,-1,-1,-1};
		 
		 for (int i=0; i<32; i++) tileList.add(new boardTile(i,new Point(tileX[i]*tileDim.width,tileY[i]*tileDim.height),
				 tileDim,colors.darkTile, new int [] {forward[0][i],forward[1][i]},new int [] {backward[0][i],backward[1][i]},this));
	 }
	
	 public void setColors(colorScheme c)
	 {
		 colors = c;
		 for (int i=0; i<32; i++) ((boardTile)tileList.get(i)).setColor(colors.darkTile);
		 repaint();
	 }
	 
	 public colorScheme getColors()
	 {
		 return colors;
	 }
	 
	 public void reset()
	 {
		 initializeTiles();
	 }
	 
	 public Point getTilePosition(int t)
	 {
		 //return new Point(tileLoc[0][t],tileLoc[1][t]);
		 //if (tileList.size() == 0) return new Point(0,0);
		 boardTile tile = tileList.get(t);
		 return new Point(tile.x,tile.y);
	 }
	 
	 public int whichTile(Point p)
	 {
		 for (int i=31;i>=0;--i)
		 {
			 if (((boardTile)tileList.get(i)).contains(p)) return i;
		 }
		 return -1;
	 }
	 
	 public int [] goForward(int tile,byte player)
	 { 
		 if (player == chipManager.player1) return new int [] {forward[0][tile],forward[1][tile]};
		 
		 return new int [] {backward[0][tile],backward[1][tile]};
	 }
	 
	 public int [] goBackward(int tile,byte player)
	 { 
		 if (player == chipManager.player2) return new int [] {forward[0][tile],forward[1][tile]};
		 
		 return new int [] {backward[0][tile],backward[1][tile]};
	 }
	 
	 public void setValidMoves(ArrayList<ArrayList<pathNode>> moves, boolean highlight)
	{
		validMoves = moves;
		ArrayList<pathNode> path;
		pathNode node;
		
		if (highlight)
		{
			//remove all highlighted tiles
			for (int i=31; i>=0; --i) tileList.get(i).highlight(false);
			
			for (int p=0;p < validMoves.size();p++)
			{
				path = validMoves.get(p);
				if (path.size() < 3) continue; 
				for (int m=0;m < path.size();m++)
				{
					node = (pathNode) path.get(m);
					tileList.get(node.tile).highlight(true);
				}
			}
		}
		
		repaint();
	}
	 
	 public void refresh()
	 {
		 repaint();
	 }
	 
	public void paintComponent(Graphics g)
	{
		super.paintComponent(g);
		Graphics2D g2d = (Graphics2D) g;
		
		//add anti-aliasing
		g2d.addRenderingHints(new RenderingHints(RenderingHints.KEY_TEXT_ANTIALIASING,
                RenderingHints.VALUE_TEXT_ANTIALIAS_ON));
		
		//reset to background color
		g2d.setColor(colors.lightTile);
		g2d.fillRect(0,0, boardDims.width-1,boardDims.height-1);
		
		//draw the checker pattern
		boardTile tile;
		for (int i=0; i<32; i++)
		{
			tile = (boardTile)tileList.get(i);
			tile.paint(g2d);
		}
		
		// draw the chips on the board
		ArrayList<chip> redChips = program.chipManager().getRedChips();
		chip rChip;
		for (int i=0; i < redChips.size(); i++)
		{
			rChip = redChips.get(i);
			if (rChip.onBoard()) rChip.paint(g2d);
		}
		ArrayList<chip> whiteChips = program.chipManager().getWhiteChips();
		chip wChip;
		for (int i=0; i < whiteChips.size(); i++)
		{
			wChip = whiteChips.get(i);
			if (wChip.onBoard()) wChip.paint(g2d);
		}
		
		//draw the selected chip again so it is on top
		if (selectedChip != null) selectedChip.paint(g2d);
	}

}
